

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"

#include "lvgl.h"

#include "esp_log.h"
#include "esp_wifi.h"

#include "custom.h"

#define EXAMPLE_ESP_MAXIMUM_RETRY  5//CONFIG_ESP_MAXIMUM_RETRY

static EventGroupHandle_t s_wifi_event_group;

#define WIFI_CONNECTED_BIT BIT0
#define WIFI_FAIL_BIT      BIT1

static const char *TAG = "wifi_sta";

static int s_retry_num = 0;

extern lv_ui guider_ui;

static void wifi_event_handler(void* arg, esp_event_base_t event_base,
                                int32_t event_id, void* event_data)
{
    if(event_base == WIFI_EVENT)
    {
        if(event_id == WIFI_EVENT_STA_START)
        {
            esp_wifi_connect();
        }
        else if (event_id == WIFI_EVENT_STA_DISCONNECTED)
        {
            xEventGroupClearBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
            if (s_retry_num < EXAMPLE_ESP_MAXIMUM_RETRY)
            {
                esp_wifi_connect();
                s_retry_num++;
                ESP_LOGI(TAG, "retry to connect to the AP");
            }
            else if(s_wifi_event_group)
            {
                xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT);
            }
            ESP_LOGI(TAG,"connect to the AP fail");
        }
        else if(event_id == WIFI_EVENT_STA_CONNECTED)
        {
            ESP_LOGI(TAG,"WIFI_EVENT_STA_CONNECTED");
            xEventGroupClearBits(s_wifi_event_group, WIFI_FAIL_BIT);
        }
        else
        {
            ESP_LOGI(TAG,"WIFI_EVENT:%d", event_id);
        }
    }
    else if (event_base == IP_EVENT)
    {
        if(event_id == IP_EVENT_STA_GOT_IP)
        {
            ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
            ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip));
            s_retry_num = 0;
            if(s_wifi_event_group) 
            {
                xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
            }
        }
        else
        {
            ESP_LOGI(TAG,"IP_EVENT:%d", event_id);
        }
    }
}

void wifi_sta_init(void)
{
    esp_err_t err;

    s_wifi_event_group = xEventGroupCreate();
    if(s_wifi_event_group == NULL)
    {
        ESP_LOGE(TAG, "Failed to create event group");
    }

    err = esp_netif_init();
    ESP_ERROR_CHECK(err);
    err = esp_event_loop_create_default();
    ESP_ERROR_CHECK(err);
    esp_netif_create_default_wifi_sta();
    
    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
    err = esp_wifi_init(&cfg);
    ESP_ERROR_CHECK(err);

    esp_event_handler_instance_t instance_any_id;
    esp_event_handler_instance_t instance_got_ip;
    err = esp_event_handler_instance_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &wifi_event_handler, NULL, &instance_any_id);
    ESP_ERROR_CHECK(err);
    err = esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &wifi_event_handler, NULL, &instance_got_ip);
    ESP_ERROR_CHECK(err);
    
    wifi_config_t wifi_config;
    err = esp_wifi_set_mode(WIFI_MODE_STA);
    ESP_ERROR_CHECK(err);
    err = esp_wifi_get_config(WIFI_IF_STA, &wifi_config);
    if(err == ESP_OK)
    {
        ESP_LOGI(TAG, "ssid:%s, password:%s, ch:%d", wifi_config.sta.ssid, wifi_config.sta.password, wifi_config.sta.channel);
        ESP_LOGI(TAG, "scan_method:%d, sort_method:%d", wifi_config.sta.scan_method, wifi_config.sta.sort_method);
        ESP_LOGI(TAG, "threshold:{rssi:%d, authmode:%d}", wifi_config.sta.threshold.rssi, wifi_config.sta.threshold.authmode);
    }
    else
    {
        ESP_LOGE(TAG, "esp_wifi_get_config failed, err:%d", err);
    }
    // esp_wifi_set_config(WIFI_IF_STA, &wifi_config);
    err = esp_wifi_start();
    ESP_ERROR_CHECK(err);
}
int wifi_sta_wait_ready(uint32_t timeout)
{
    uint32_t evt = xEventGroupWaitBits(s_wifi_event_group, WIFI_CONNECTED_BIT, false, true, timeout);
    if(evt & BIT31)
    {
        return evt;
    }
    if(evt & WIFI_CONNECTED_BIT)
    {
        return ESP_OK;
    }
    return ESP_FAIL;
}
void wifi_sta_scan_aps_start(void)
{
    wifi_ap_record_t ap_info[16];
    uint16_t num;
    ESP_LOGI(TAG, "wifi_sta_scan_aps_start");
    // esp_wifi_stop();
    esp_wifi_disconnect();
    esp_wifi_scan_start(NULL, true);
    num = 0;
    esp_wifi_scan_get_ap_num(&num);
    if(num > sizeof(ap_info)/sizeof(ap_info[0]))
    {
        num = sizeof(ap_info)/sizeof(ap_info[0]);
    }
    esp_wifi_scan_get_ap_records(&num, ap_info);
    for(uint16_t i=0; i<num; i++)
    {
        ESP_LOGI(TAG, "[%d] ssid:%s, rssi:%d", i, ap_info[i].ssid, ap_info[i].rssi);
    }
    custom_set_wifi_list(&guider_ui, ap_info, num);
}
void wifi_sta_scan_aps_stop(void)
{
    esp_err_t err;
    esp_wifi_scan_stop();
    // err = esp_wifi_start();
    // ESP_ERROR_CHECK(err);
    ESP_LOGI(TAG, "wifi_sta_scan_aps_stop");
}

static const char *auth_method_name[] =
{
    [WIFI_AUTH_OPEN]            = "OPEN",
    [WIFI_AUTH_OWE]             = "OWE",
    [WIFI_AUTH_WEP]             = "WEP",
    [WIFI_AUTH_WPA_PSK]         = "WPA_PSK",
    [WIFI_AUTH_WPA2_PSK]        = "WPA2_PSK",
    [WIFI_AUTH_WPA_WPA2_PSK]    = "WPA_WPA2_PSK",
    [WIFI_AUTH_ENTERPRISE]      = "ENTERPRISE",
    [WIFI_AUTH_WPA3_PSK]        = "WPA3_PSK",
    [WIFI_AUTH_WPA2_WPA3_PSK]   = "WPA2_WPA3_PSK",
    [WIFI_AUTH_WPA3_ENT_192]    = "WPA3_ENT_192",
    [WIFI_AUTH_WAPI_PSK]        = "WAPI_PSK"
};
const char *wifi_sta_auth_method_name(int authmode)
{
    const char *automode_str = "UNKNOWN";
    if(authmode >= WIFI_AUTH_OPEN && authmode < WIFI_AUTH_MAX)
    {
        automode_str = auth_method_name[authmode];
    }
    return automode_str;
}
int wifi_sta_auth_method_type(const char *auth)
{
    for(int i=0; i<sizeof(auth_method_name)/sizeof(auth_method_name[0]); i++)
    {
        if(memcmp(auth_method_name[i], auth, strlen(auth)+1) == 0)
        {
            return i;
        }
    }
    return -1;
}
void wifi_sta_connect_new_ap(const char *ap, const char *pw, int auth)
{
    wifi_config_t wifi_config;
    esp_err_t err;
    if(ap == NULL)
    {
        ESP_ERROR_CHECK(ESP_FAIL);
    }
    memset(&wifi_config, 0, sizeof(wifi_config));
    memcpy(wifi_config.sta.ssid, ap, strlen(ap)+1);
    if(pw)
    {
        memcpy(wifi_config.sta.password, pw, strlen(pw)+1);
    }
    else
    {
        wifi_config.sta.password[0] = 0;
    }
    wifi_config.sta.threshold.authmode = auth;
    ESP_LOGI(TAG, "new ap:%s,%s,%d", ap, pw, auth);
    esp_wifi_stop();
    err = esp_wifi_set_config(WIFI_IF_STA, &wifi_config);
    ESP_ERROR_CHECK(err);
    esp_wifi_start();
}

